package com.ngovanhau.justsort.model;

import org.anddev.andengine.engine.Engine;
import org.anddev.andengine.entity.modifier.MoveYModifier;
import org.anddev.andengine.entity.scene.Scene;
import org.anddev.andengine.entity.sprite.Sprite;
import org.anddev.andengine.input.touch.TouchEvent;
import org.anddev.andengine.opengl.texture.region.TextureRegion;

import com.ngovanhau.justsort.MainGameActivity;
import com.ngovanhau.justsort.MainMenuActivity;
import com.ngovanhau.justsort.MySprite;
import com.ngovanhau.justsort.ProgressBar;
import com.ngovanhau.justsort.control.ValueControl;
import com.ngovanhau.justsort.item.config.MyConfig;
import com.ngovanhau.justsort.mystatic.TypeMove;

import android.graphics.Point;
import android.util.Log;

public class MyNumber extends MySprite {

	private Sprite number_wrong;
	private Sprite number_right;

	private int pX = 0, pY = 0;

	private int i = -1, j = -1;

	public int value = 0;

	public boolean isRight;

	MyNumber numTemp;

	long timeDown;
	boolean isDown;

	CounterHandler mHandler_Counter;

	TypeMove TYPE_MOVE;// 0: no; 1: ahead; 2: cross;

	boolean isFirst = true;
	boolean isChanged = false;

	public MyNumber(MainGameActivity mainGame) {
		this.mainGame = mainGame;
		isRight = false;
		isDown = false;
		TYPE_MOVE = TypeMove.NONE;
	}

	// -----------------------------------------------------
	public void onLoadScene(Scene mScene, Engine engine, TextureRegion item_TR,
			TextureRegion item_red_TR, int value, int x, int y) {
		this.engine = engine;
		this.scene = mScene;

		this.value = value;
		this.pX = x;
		this.pY = y;
		this.setIJ(i, j);

		this.number_wrong = new Sprite(pX, -100,
				MyConfig.WIDTH_NUMBER /*- 5 * MyConfig.RACE_WIDTH*/,
				MyConfig.HEIGHT_NUMBER /*-  5 * MyConfig.RACE_WIDTH*/,
				item_TR) {
			@Override
			public boolean onAreaTouched(final TouchEvent pTouchEvent,
					final float pTouchLocalX, final float pTouchLocalY) {
				touchNumber(pTouchEvent, pTouchLocalX, pTouchLocalY);
				return true;
			}
		};
		scene.setZIndex(0);
		scene.sortChildren();
		scene.attachChild(number_wrong);
		scene.registerTouchArea(number_wrong);

		this.number_right = new Sprite(pX, -100,
				MyConfig.WIDTH_NUMBER /*-  5 * MyConfig.RACE_WIDTH*/,
				MyConfig.HEIGHT_NUMBER /*-  5 * MyConfig.RACE_WIDTH*/,
				item_red_TR) {
			@Override
			public boolean onAreaTouched(final TouchEvent pTouchEvent,
					final float pTouchLocalX, final float pTouchLocalY) {
				touchNumber(pTouchEvent, pTouchLocalX, pTouchLocalY);
				return true;
			}
		};
		scene.setZIndex(1);
		scene.sortChildren();
		scene.attachChild(number_right);
		scene.registerTouchArea(number_right);

		isRight = checkRight();
		isFirst = false;
	}

	public void moveFirst() {
		float time = 4f;
		final MoveYModifier moveYModifier = new MoveYModifier(time, -200,
				this.pY);
		number_right.registerEntityModifier(moveYModifier);
		number_wrong.registerEntityModifier(moveYModifier);
	}

	public void touchNumber(TouchEvent pTouchEvent, float pTouchLocalX,
			float pTouchLocalY) {
		if (ValueControl.isTouchNumber) {//neu co the cham dc
			if (isRight) {
				switch (pTouchEvent.getAction()) {
				case TouchEvent.ACTION_MOVE:
					if (isDown) {
						setPositionTemp(number_right.getX() + pTouchLocalX
								- number_right.getWidth() / 2,
								number_right.getY() + pTouchLocalY
										- number_right.getHeight() / 2);
						responseMove();
					} else {
						setAllPosition(pX, pY);
					}
					break;
				case TouchEvent.ACTION_UP:
					// put it to position empty
					if (isDown) {
						responseUp();
					}
					break;
				case TouchEvent.ACTION_DOWN:
					responseDown();
				default:
					break;
				}
			} else {
				switch (pTouchEvent.getAction()) {
				case TouchEvent.ACTION_MOVE:
					if (isDown) {
						setPositionTemp(number_wrong.getX() + pTouchLocalX
								- number_wrong.getWidth() / 2,
								number_wrong.getY() + pTouchLocalY
										- number_wrong.getHeight() / 2);
						responseMove();
					} else {
						setAllPosition(pX, pY);//
					}
					break;
				case TouchEvent.ACTION_UP:
					if (isDown) {
						responseUp();
					}
					break;
				case TouchEvent.ACTION_DOWN:
					responseDown();
					break;
				default:
					break;
				}
			}
		}
	}

	/**
	 * when move number check and update number
	 */
	public void responseMove() {
		Point p = Matrix2D.getCell(
				(int) (number_wrong.getX() + number_wrong.getWidth() / 2),
				(int) (number_wrong.getY() + number_wrong.getHeight() / 2));

		checkAvailableCell(p);
	}

	private void checkAvailableCell(Point p) {
		if (p.x == i) {// left, right
			if (p.y == j - 1 && j > 0) {
				TYPE_MOVE = TypeMove.LEFT;
			} else if (p.y == j + 1 && j < LevelSetting.columnLevel - 1) {
				TYPE_MOVE = TypeMove.RIGHT;
			}
		} else if (p.x == i - 1) {// top, top-left, top-right
			if (p.y == j - 1 && i > 0 && j > 0) {
				TYPE_MOVE = TypeMove.TOP_LEFT;
			} else if (p.y == j && i > 0) {
				TYPE_MOVE = TypeMove.TOP;
			} else if (p.y == j + 1 && i > 0
					&& j < LevelSetting.columnLevel - 1) {
				TYPE_MOVE = TypeMove.TOP_RIGHT;
			}
		} else if (p.x == i + 1) {// bottom-left, bottom, bottom-right
			if (p.y == j - 1 && i < LevelSetting.rowLevel - 1 && j > 0) {
				TYPE_MOVE = TypeMove.BOTTOM_LEFT;
			} else if (p.y == j && i < LevelSetting.rowLevel - 1) {
				TYPE_MOVE = TypeMove.BOTTOM;
			} else if (p.y == j + 1 && i < LevelSetting.rowLevel - 1
					&& j < LevelSetting.columnLevel - 1) {
				TYPE_MOVE = TypeMove.BOTTOM_RIGHT;
			}
		} else {
			TYPE_MOVE = TypeMove.NONE;
		}
		
		if (!inCircle((p.y + 0.5) * MyConfig.WIDTH_NUMBER + MyConfig.X_START, (p.x + 0.5) * MyConfig.HEIGHT_NUMBER + MyConfig.Y_START, number_wrong.getX()+ number_wrong.getWidth() / 2, number_wrong.getY()+ number_wrong.getHeight() / 2, (MyConfig.WIDTH_NUMBER+ MyConfig.HEIGHT_NUMBER)/4)){
			TYPE_MOVE = TypeMove.NONE;
		}
		
		if (TYPE_MOVE != TypeMove.NONE) {// move
			processNumber();
		}
	}

	private boolean inCircle(double x1, double y1, double x2, double y2, double r){
		double a = x1 > x2 ? (x1 - x2) : (x2 - x1);
		double b = y1 > y2 ? (y1 - y2) : (y2 - y1);
		double d = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
		
		return d < r ? true : false;
	}
	
	public void processNumber() {
		switch (TYPE_MOVE) {
		case LEFT:
			numTemp = mainGame.map[i][j - 1];
			break;
		case TOP_LEFT:
			numTemp = mainGame.map[i - 1][j - 1];
			break;
		case TOP:
			numTemp = mainGame.map[i - 1][j];
			break;
		case TOP_RIGHT:
			numTemp = mainGame.map[i - 1][j + 1];
			break;
		case RIGHT:
			numTemp = mainGame.map[i][j + 1];
			break;
		case BOTTOM_RIGHT:
			numTemp = mainGame.map[i + 1][j + 1];
			break;
		case BOTTOM:
			numTemp = mainGame.map[i + 1][j];
			break;
		case BOTTOM_LEFT:
			numTemp = mainGame.map[i + 1][j - 1];
			break;
		default:
			// nothing
			break;
		}
		swapNumber();
	}

	public void swapNumber() {
		if (numTemp != null) {
			int tg_X = numTemp.pX, tg_Y = numTemp.pY;
			numTemp.setAllPosition(this.pX, this.pY);
			this.setPosition(tg_X, tg_Y);
			mainGame.swapNumber(numTemp.i, numTemp.j, this.i, this.j);
			isChanged = true;
		}
		numTemp = null;
		TYPE_MOVE = TypeMove.NONE;
	}

	/**
	 * when press down number
	 */
	public void responseDown() {
		setIsDown(true);
		setPositionTemp(pX + 30, pY - 30);
		if (isRight) {
			number_right.setZIndex(100);
		} else {
			number_wrong.setZIndex(100);
		}
		scene.sortChildren();
		mHandler_Counter = new CounterHandler();
		mHandler_Counter.start();
	}

	/**
	 * set position for this number put it to empty oval
	 */
	public void responseUp() {
		synchronized (this) {
			setIsDown(false);
			setAllPosition(pX, pY);
			
			if(isChanged){
				mainGame.checkLevelCompleted();
			}
			
			isChanged = false;
			timeDown = -1;
		}
	}

	public boolean checkRight() {
		int index = i * LevelSetting.columnLevel + j + 1;
		if (index == value) {
			if (!isRight && !isFirst) {
				isRight = true;
				MainMenuActivity.sound.playCorrect();
				mainGame.addBonus();
			}
			this.number_wrong.setVisible(false);
			this.number_right.setVisible(true);
			number_wrong.setZIndex(0);
			number_right.setZIndex(1);
			scene.sortChildren();
			return true;
		} else {
			this.number_right.setVisible(false);
			this.number_wrong.setVisible(true);
			number_right.setZIndex(0);
			number_wrong.setZIndex(1);
			scene.sortChildren();
			isRight = false;
			return false;
		}
	}

	/*
	 * set gia tri cho bien pX pY
	 */
	public void setPosition(int x, int y) {
		this.pX = x;
		this.pY = y;

	}

	/*
	 * set vi tri cho ta
	 */
	public void setAllPosition(int x, int y) {
		setPosition(x, y);
		setPosition();
		number_right.setZIndex(1);
		number_wrong.setZIndex(1);
		scene.sortChildren();
	}

	/*
	 * set vi tri cho 2 hinh anh cua so do
	 */
	public void setPosition() {
		number_wrong.setPosition(pX, pY);
		number_right.setPosition(pX, pY);
	}

	public void setPositionTemp(float x, float y) {
		number_right.setPosition(x, y);
		number_wrong.setPosition(x, y);
	}

	public void setIJ(int i, int j) {
		this.i = i;
		this.j = j;
	}

	public void setXY(int x, int y) {
		this.pX = x;
		this.pY = y;
	}

	public void setIsDown(boolean state) {
		synchronized (this) {
			isDown = state;
		}
	}

	class CounterHandler extends Thread {
		public void run() {
			float step = (ProgressBar.width_rect / (LevelSetting.TimeOutMoveCurrentLevel * 1000f)) * 200f;
			float count = ProgressBar.width_rect / step + 1;
			Log.d("drag number", "timeout drag" + count);
			while (isDown) {
				try {
					Thread.sleep(200);
					count--;
					mainGame.updateProgressBar(step);
					
					if (count <= 0 ) {
						responseUp();
						break;
					}
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			mainGame.resetProgressBar();
		}
	}

	public void onDestroy() {
		engine.runOnUpdateThread(new Runnable() {
			@Override
			public void run() {
				scene.unregisterTouchArea(number_wrong);
				scene.detachChild(number_wrong);
				scene.unregisterTouchArea(number_right);
				scene.detachChild(number_right);
			}
		});
	}
};